在開發過程中,我們有時會不小心將不該加入 Git 的檔案 commit 進 repo,例如:
.terraform/
目錄下的 provider binary)即使後來在 .gitignore
排除了這些檔案,它們仍然會殘留在 Git 的歷史紀錄。這時候我們可以使用 git filter-repo
來重寫整個 Git history,從歷史紀錄中徹底移除這些資料。
git filter-repo
是官方推薦的 Python 開源工具,可以用來:
git filter-repo
的特點是:
git filter-repo
?目前常見的 Git 歷史重寫工具如下:
工具 | 優點 | 缺點 |
---|---|---|
git filter-branch |
內建、可自訂 shell script | 非常慢、語法繁瑣、容易出錯 |
git filter-repo |
快速、安全、彈性高 | 需額外安裝 |
BFG Repo-Cleaner | 操作簡單、速度快 | 無法細緻控制特定檔案/作者 |
✅ 在
git filter-branch
官方手冊的 WARNING 中,指出其性能與安全上的問題,並推薦使用git filter-repo
取代。
macOS
brew install git-filter-repo
Ubuntu/Debian
sudo apt install git-filter-repo
跨平台(使用 pip)
pip install git-filter-repo
✅ 安裝成功測試
git filter-repo --analyze
如果你不幸安裝失敗(像我一樣 😭),這裡提供不安裝的替代方案:
git-filter-repo
(沒有副檔名)放入 Git 安裝路徑。
C:\Program Files\Git\mingw64\libexec\git-core
git-filter-repo
的第一行(Shebang line),手動指定你的 python.exe
路徑:
#!C:\Python311\python.exe
git filter-repo
移除指定檔案⚠️使用這個工具會重寫 Git history,所以執行前記得先備份!
git filter-repo --path <path> --invert-paths
--path
: 指定要移除的檔案或資料夾。--invert-paths
: 表示保留其他內容、移除指定的 path。# 移除 `key.json`(不包含子目錄底下的同名檔案)
git filter-repo --path key.json --invert-paths --force
# 移除 `keys/` 資料夾下的所有檔案。
git filter-repo --path keys/ --invert-paths
# 移除與 glob 相符的檔案。
git filter-repo --path-glob */logs/ --invert-paths
# 移除與 RegEx 相符的檔案。
git filter-repo --path-regex .*/logs/application.[0-9]+.log --invert-paths
# 移除所有路徑底下的 `.DS_Store` 檔案。
git filter-repo --path .DS_Store --use-base-name --invert-paths
在官方文件的說明中,提到可以使用單引號包住
<path>
,但是我自己用的時候,如果有加單引號就會 match 失敗。
因此實際使用前,建議建立一個測試用的 Git Repo,確認如何下指令可以達成你想要的效果哦!
# 更新 remote URL
git remote set-url origin <remote-repo-url>
# 強制推送新的 history
git push --force --all
git init
echo secrets > key.json
git add *
git commit -m "feat: add key.json"
echo hello > file1.txt
git add *
git commit -m "feat: add file1"
echo hello > file2.txt
git add *
git commit -m "feat: add file2"
mkdir logs
echo hello > logs\app.0.log
echo hello > logs\app.1.log
git add *
git commit -m "feat: add logs"
> git ls-files
file1.txt
file2.txt
key.json
logs/app.0.log
logs/app.1.log
> git log --oneline
bf4d019 (HEAD -> main) feat: add logs
f6242d9 feat: add file2
2d8d990 feat: add file1
a1e210b feat: add key.json
key.json
:
git filter-repo --path key.json --invert-paths --force
.log
的檔案。
git filter-repo --path-glob **/*.log --invert-paths
> git ls-files
file1.txt
file2.txt
> git log --oneline
2bf3da8 (HEAD -> main) feat: add file2
a56e671 feat: add file1
最近公司從 Gitea 移轉到 GitHub,有改寫 git history 的需求,發現中文圈有很多 git-filter-branch
的文章,但關於 git-filter-repo
這個工具的文章不多,尤其是 Windows 安裝失敗的排除方式……
因此花了一點時間撰寫這篇文章,希望能給大家帶來一些幫助 :D